package com.rengwuxian.coursecoroutines._2_structured_concurrency

import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlin.concurrent.thread
import kotlin.coroutines.EmptyCoroutineContext

/**
 * CoroutineExceptionHandler
 * CoroutineExceptionHandle、try/catch、launch{}、thread{}
 *
 * 协程的try/catch：
 * scope.launch {
 *    try {
 *        throw IllegalStateException("Wrong user!")
 *    } catch (e: IllegalStateException) {
 *    }
 * }
 * 只能在协程内部捕获异常，如果将try/catch挪到launch的外面，则无法捕获协程内部的异常，因为try/catch无法穿透到协程内部，只会包含启动协程的部分。
 * 类似于线程这样只能捕获到启动异常，是无法捕获线程内部异常的。代码示例如下：
 *   try {
 *     val thread = object : Thread() {
 *       override fun run() {
 *         throw RuntimeException("Error!")
 *       }
 *     }
 *     thread.start()
 *   } catch (e: Exception) {
 *     println("Caught $e")
 *   }
 * 协程使用很丝滑，写try/catch时需要注意有效范围。
 *
 * 协程的异常捕获：CoroutineExceptionHandler示例打印log如下：
 * Caught java.lang.RuntimeException: Error!
 *
 * 也是符合协程的结构化特性的：
 * CoroutineExceptionHandler只能（必须）设置给最顶层的父协程，才能生效。
 * 而设置在子协程上，没有任何作用，会继续抛异常，无法抓住。
 *
 * 这么设计合理吗？见下一章节内容。
 */
fun main() = runBlocking<Unit> {
  val scope = CoroutineScope(EmptyCoroutineContext)
  val handler = CoroutineExceptionHandler { _, exception ->
    println("Caught $exception")
  }
  scope.launch(handler) {
    launch {
      throw RuntimeException("Error!")
    }
    launch {

    }
  }
  delay(10000)
}